package odie

import (
	"errors"
	"net/url"
	"io"
	"fmt"
)

type patternSet map[string]Pattern

// Use w to write back to the client who made this request.
// vars is populated with the variables recognized in the query.
// For example, "my name is $name" matches "my name is Ryanne" and causes vars.Get("name") == "Ryanne".
type HandlerFunc func(w *ResponseWriter, req *Request, vars Context)

type Matcher struct {
	handlers map[string]HandlerFunc
	Patterns patternSet
	done bool
}

func NewMatcher() *Matcher {

	return &Matcher{make(map[string]HandlerFunc), make(patternSet), false}
}

func (m *Matcher) Keywords() (words []string) {

	dict := make(map[string]bool)

	for _, p := range m.Patterns {

		for w := range p.Keywords() {
			dict[w] = true
		}
	}

	for w := range dict {

		words = append(words, w)
	}

	return
}

func (m *Matcher) Add(p string, handler HandlerFunc) (pat Pattern, err error) {

	pat = Parse(p)
	p = pat.String()

	m.Patterns[p] = pat

	_, ok := m.handlers[p]

	if ok {
		panic("already have a handler for that pattern")
	}

	m.handlers[p] = handler

	return
}

func (m *Matcher) Match(q string) (handler HandlerFunc, vals url.Values, err error) {

	best := -1

	for s, p := range m.Patterns {

		v := make(url.Values)

		score, err := p.Match(q, v)

		if err != nil {
			continue
		}

		if score <= best {
			continue
		}

		best = score
		vals = v
		handler = m.handlers[s]
	}

	if best < 0 {
		err = errors.New("no match")
	}
	

	return
}

func (m *Matcher) Write(w io.Writer) error {

	for p, _ := range m.Patterns {
		fmt.Fprintf(w, "%s\n", p)
	}

	return nil
}

